using System;
using Glue.Converters;

namespace Glue.Internals
{
    internal class NullableTypeMapper:IConverter
    {
        private readonly Type leftType;
        private readonly Type rightType;

        private readonly NullableRuntimeType nullableType;

        /// <require>one type is the nullable version of the other</require>
        public NullableTypeMapper(Type t1, Type t2)
        {
            leftType = t1;
            rightType = t2;
            if (NullableRuntimeType.IsNullable(t1))
                nullableType = CreateNullableTypeAndValidate(t1, t2);
            else if (NullableRuntimeType.IsNullable(t2))
                nullableType = CreateNullableTypeAndValidate(t2, t1);
            else
                throw new GlueException("Bug: neither '"+t1.Name+"' or '"+t2.Name+"' are nullable types, but the system seems to think so.. Please report");
        }

        private NullableRuntimeType CreateNullableTypeAndValidate(Type t1, Type t2)
        {
            var nullable = new NullableRuntimeType(t1);
            if (t2 != nullable.GetUnderlyingType())
                throw new GlueException("Bug: '"+t1+"' is not the nullable version of '"+t2+"'. Please report");
            return nullable;
        }

        public object Map(object from, object to)
        {
            return from ?? nullableType.GetDefaultValue();
        }

        public Type LeftType
        {
            get { return leftType; }
        }

        public Type RightType
        {
            get { return rightType; }
        }
    }
}